package springinpractice.ch8.contact.service;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.log4j.Logger;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.velocity.VelocityEngineUtils;
import org.springframework.util.Assert;

import springinpractice.ch8.contact.dao.UserMessageDao;
import springinpractice.ch8.contact.model.UserMessage;

/**
 * @author Willie Wheeler and John Wheeler
 * Book : 'Spring In Practice' [Book written by Willie Wheeler and John Wheeler]
 **/

@Service
@Transactional(
	propagation = Propagation.REQUIRED,
	isolation = Isolation.DEFAULT,
	readOnly = true)
public class ContactServiceImpl implements ContactService {
	private static final String CONFIRMATION_TEMPLATE_PATH = "contactConfirm.vm";
	private static final String USER_MSG_TEMPLATE_PATH = "contactUserMessage.vm";
	
	@SuppressWarnings("unused")
	private static final Logger log = Logger.getLogger(ContactServiceImpl.class);
	
	private UserMessageDao userMsgDao;
	private JavaMailSender mailSender;
	private VelocityEngine velocityEngine;
	private boolean sendConfirmation;
	private boolean notifyAdmin;
	private String noReplyEmailAddr;
	private String adminEmailAddr;
	
	
	// ========================================================================
	// Dependency injection methods
	// ========================================================================
	
	public void setUserMessageDao(UserMessageDao userMsgDao) {
		this.userMsgDao = userMsgDao;
	}
	
	public void setMailSender(JavaMailSender mailSender) {
		this.mailSender = mailSender;
	}
	
	public void setVelocityEngine(VelocityEngine velocityEngine) {
		this.velocityEngine = velocityEngine;
	}
	
	@Required
	public void setSendConfirmation(boolean sendConfirmation) {
		this.sendConfirmation = sendConfirmation;
	}
	
	@Required
	public void setNotifyAdmin(boolean notifyAdmin) {
		this.notifyAdmin = notifyAdmin;
	}
	
	public void setNoReplyEmailAddress(String noReplyEmailAddr) {
		this.noReplyEmailAddr = noReplyEmailAddr;
	}
	
	public void setAdminEmailAddress(String adminEmailAddr) {
		this.adminEmailAddr = adminEmailAddr;
	}
	
	
	// ========================================================================
	// Service methods
	// ========================================================================
	
	@Transactional(readOnly = false)
	public void saveUserMessage(UserMessage userMsg) {
		Assert.notNull(userMsg, "userMsg can't be null");
		userMsgDao.save(userMsg);
		if (sendConfirmation) {
			MimeMessage mimeMsg = createEmail(
					userMsg, CONFIRMATION_TEMPLATE_PATH,
					"Confirmation message", userMsg.getEmail(),
					noReplyEmailAddr, null);
			sendEmail(mimeMsg);
		}
		if (notifyAdmin) {
			MimeMessage mimeMsg = createEmail(
					userMsg, USER_MSG_TEMPLATE_PATH,
					"User message", adminEmailAddr,
					userMsg.getEmail(), userMsg.getName());
			sendEmail(mimeMsg);
		}
	}
	
	private MimeMessage createEmail(UserMessage userMsg, String templatePath,
			String subject, String toEmail, String fromEmail, String fromName) {
		
		MimeMessage mimeMsg = mailSender.createMimeMessage();
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("userMessage", userMsg);
		String text = VelocityEngineUtils.mergeTemplateIntoString(
			velocityEngine, templatePath, model);
		text = text.replaceAll("\n", "<br>");
		
		try {
			MimeMessageHelper helper = new MimeMessageHelper(mimeMsg);
			helper.setSubject(subject);
			helper.setTo(toEmail);
			
			if (fromName == null) {
				helper.setFrom(fromEmail);
			} else {
				try {
					helper.setFrom(fromEmail, fromName);
				} catch (UnsupportedEncodingException e) {
					helper.setFrom(fromEmail);
				}
			}
			
			helper.setSentDate(userMsg.getDateCreated());
			helper.setText(text, true);
		} catch (MessagingException e) {
			throw new RuntimeException(e);
		}
		
		return mimeMsg;
	}
	
	private void sendEmail(MimeMessage mimeMsg) {
		log.info("Sending e-mail");
		mailSender.send(mimeMsg);
	}
}
